﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Office.Interop.Excel;

namespace WFL.Office.Excel
{
    public class ExcelRange : DisposableSite
    {
        private readonly object _lock = new object();

        public ExcelRange this[object rowIndex = null, object columnIndex = null]
        {
            get
            {
                ExcelRange item = new ExcelRange((Range)_range[rowIndex ?? Type.Missing, columnIndex ?? Type.Missing]);
                Trace(item);
                return item;
            }
        }

        public RangeIndex Range
        {
            get;
            private set;
        }

        private ExcelBorders _borders;
        public ExcelBorders Borders
        {
            get
            {
                if (_borders == null)
                {
                    lock (_lock) { if (_borders == null) { _borders = new ExcelBorders(_range.Borders); } }
                }
                return _borders;
            }
        }

        private ExcelRange _columns;
        public ExcelRange Columns
        {
            get
            {
                if (_columns == null)
                {
                    lock (_lock) { if (_columns == null) { _columns = new ExcelRange(_range.Columns); } }
                }
                return _columns;
            }
        }

        private ExcelRange _entireColumn;
        public ExcelRange EntireColumn
        {
            get
            {
                if (_entireColumn == null)
                {
                    lock (_lock) { if (_entireColumn == null) { _entireColumn = new ExcelRange(_range.EntireColumn); } }
                }
                return _entireColumn;
            }
        }

        private ExcelRange _cells;
        public ExcelRange Cells
        {
            get
            {
                if (_cells == null)
                {
                    lock (_lock) { if (_cells == null) { _cells = new ExcelRange(_range.Cells); } }
                }
                return _cells;
            }
        }


        #region 样式属性

        public HAlign HAlign
        {
            get { return (HAlign)_range.HorizontalAlignment; }
            set { _range.HorizontalAlignment = value; }
        }

        public VAlign VAlign
        {
            get { return (VAlign)_range.VerticalAlignment; }
            set { _range.VerticalAlignment = value; }
        }

        public bool WrapText
        {
            get { return (bool)_range.WrapText; }
            set { _range.WrapText = value; }
        }

        public double RowHeight
        {
            get { return (double)_range.RowHeight; }
            set { _range.RowHeight = value; }
        }

        public double ColumnWidth
        {
            get { return (double)_range.ColumnWidth; }
            set { _range.ColumnWidth = value; }
        }

        private ExcelFont _font;
        public ExcelFont Font
        {
            get 
            {
                if (_font == null)
                {
                    lock (_lock) { if (_font == null) { _font = new ExcelFont(_range.Font); } }
                }
                return _font;
            }
        }

        #endregion


        private Range _range;

        private ExcelApplication _application;
        public ExcelApplication Application
        {
            get { return _application; }
            internal set { _application = value; }
        }

        internal ExcelRange(Range range)
        {
            _range = range;
            Range = new RangeIndex(GetRange);
        }

        private ExcelRange GetRange(object cell1, object cell2)
        {
            ExcelRange item = new ExcelRange(_range.get_Range(cell1, cell2 ?? Type.Missing)) { Application = Application };
            Trace(item);
            return item;
        }


        #region SetValue

        public void SetValue(object value, object rangeValueDataType = null)
        {
            //临时处理
            _range.Value[rangeValueDataType ?? Type.Missing] = value is Array ? value : new string[,] { { value.ToString() } };
        }

        public void SetValue(string cell, object value, object rangeValueDataType = null)
        {
            Range range = (Range)_range.get_Range(cell);
            try
            {
                //临时处理
                range.Value[rangeValueDataType ?? Type.Missing] = new string[,] { { value.ToString() } };
            }
            finally
            {
                Marshal.ReleaseComObject(range);
                range = null;
            }
        }

        public void SetValue(int rowIndex, int columnIndex, object value, object rangeValueDataType = null)
        {
            Range range = (Range)_range.get_Item(rowIndex, columnIndex);
            try
            {
                //临时处理
                range.Value[rangeValueDataType ?? Type.Missing] = new string[,] { { value.ToString() } };
            }
            finally
            {
                Marshal.ReleaseComObject(range);
                range = null;
            }
        }

        #endregion


        #region GetValue

        public object GetValue(object rangeValueDataType = null)
        {
            return _range.Value[rangeValueDataType ?? Type.Missing];
        }

        public object GetValue(string cell, object rangeValueDataType = null)
        {
            Range range = (Range)_range.get_Range(cell);
            try
            {
                return range.Value[rangeValueDataType ?? Type.Missing];
            }
            finally
            {
                Marshal.ReleaseComObject(range);
                range = null;
            }
        }

        public object GetValue(int rowIndex, int columnIndex, object rangeValueDataType = null)
        {
            Range range = (Range)_range.get_Item(rowIndex, columnIndex);
            try
            {
                return range.Value[rangeValueDataType ?? Type.Missing];
            }
            finally
            {
                Marshal.ReleaseComObject(range);
                range = null;
            }
        }

        #endregion


        /// <summary>
        /// 合并单元格
        /// </summary>
        /// <param name="across">是否每行独立合并</param>
        public void Merge(bool across = false)
        {
            _range.Merge(across);
        }

        public void UnMerge()
        {
            _range.UnMerge();
        }

        public object AutoFit()
        {
            return _range.AutoFit();
        }

        public object Delete()
        {
            return _range.Delete();
        }

        public object Delete(DeleteShiftDirection shift)
        {
            return _range.Delete(shift);
        }

        public object Copy(ExcelRange destination = null)
        {
            return _range.Copy(destination != null ? destination._range : Type.Missing);
        }

        public object Insert(InsertShiftDirection? shift = null, InsertFormatOrigin? copyOrigin = null)
        {
            return _range.Insert(shift ?? Type.Missing, copyOrigin ?? Type.Missing);
        }

        protected override void Dispose(bool disposing)
        {
            if (_range != null)
            {
                if (disposing)
                {
                    ExcelFont font = _font;
                    if (font != null)
                    {
                        _font = null;
                        font.Dispose();
                    }
                    ExcelBorders borders = _borders;
                    if (borders != null)
                    {
                        _borders = null;
                        borders.Dispose();
                    }
                    ExcelRange columns = _columns;
                    if (columns != null)
                    {
                        _columns = null;
                        columns.Dispose();
                    }
                    ExcelRange entireColumn = _entireColumn;
                    if (entireColumn != null)
                    {
                        _entireColumn = null;
                        entireColumn.Dispose();
                    }
                    ExcelRange cells = _cells;
                    if (cells != null)
                    {
                        _cells = null;
                        cells.Dispose();
                    }
                    Marshal.ReleaseComObject(_range);
                }
                _range = null;
                _application = null;
                base.Dispose(disposing);
            }
        }
    }
}
